package com.examination.to.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.examination.to.entity.Answer;
import com.examination.to.entity.ExamRecord;
import com.examination.to.entity.Question;
import com.examination.to.mapper.AnswerMapper;
import com.examination.to.mapper.ExamRecordMapper;
import com.examination.to.mapper.QuestionMapper;
import com.examination.to.service.ExamRecordService;
import com.examination.to.util.Result;
import com.examination.to.vo.QuestionVo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;


import java.text.NumberFormat;
import java.util.*;



import java.util.ArrayList;

import java.util.List;


/**
 * author:FC
 * date:2020/5/14 20:00
 */
@Service
public class ExamRecordServiceImpl extends ServiceImpl<ExamRecordMapper, ExamRecord> implements ExamRecordService {

    private static final String FIRST_SCOPE = "[0~20)";
    private static final String SECOND_SCOPE = "[20~40)";
    private static final String THIRD_SCOPE = "[40~60)";
    private static final String FORTH_SCOPE = "[60~80)";
    private static final String FIFTH_SCOPE = "[80~100)";

    @Autowired
    private QuestionMapper questionMapper;

    @Autowired
    private AnswerMapper answerMapper;

    @Autowired
    private ExamRecordMapper examRecordMapper;

    public Result addExamRecord(Integer id,String examtime, List<QuestionVo> questionVoList
    ,String answername,String starttime,String endtime){
        Result result = new Result();
        result.setCode(-1);
        result.setDetail(null);
        try {
            ExamRecord examRecord = new ExamRecord();
            QueryWrapper<Answer> answerQueryWrapper = new QueryWrapper<>();
            answerQueryWrapper.eq("examid",id);
            //用来评判对照的响应试卷的答案列表
            List<Answer> answers = answerMapper.selectList(answerQueryWrapper);
            //遍历答案的index
            int k = 0;
            //设置试卷总分
            Integer totalscore = 0;
            examRecord.setExamtime(examtime);
            //存储打错的题的id
            StringBuffer errquestionids = new StringBuffer();
            //存储试题对应的id
            StringBuffer questionids = new StringBuffer();
            //存储用户答题内容
            StringBuffer useranswer = new StringBuffer();
            //存储客观题答案
            StringBuffer scores = new StringBuffer();
            for (QuestionVo questionVo : questionVoList) {
                //存储用户答题的答案
                StringBuffer stringBuffer = new StringBuffer();
                //因为用的是id排序，且id是递增的，所以该行找到最好一个数据的id值后续添加的数据id加一即可
                ExamRecord lastExamRecord = examRecordMapper.findLast();
                if (lastExamRecord == null){
                    examRecord.setRecordid(1);
                }else {
                    examRecord.setRecordid(examRecordMapper.findLast().getRecordid()+1);
                }
                if (k == questionVoList.size() - 1){
                    questionids.append(questionVo.getQuestionid());
                }else {
                    questionids.append(questionVo.getQuestionid()).append(",");
                }
                examRecord.setExamid(id);
                //比对答案的时候，类型为5的用户信息是没有答案的，为了保持对比一致跳过
                if (questionVo.getQuestiontype() == 5){
                    useranswer.append(questionVo.getQuestionid()).append("、").append(questionVo.getStuinfo()).append(";");
                    scores.append(0).append(",");
                    continue;
                }else {
                    if (questionVo.getQuestiontype() == 1){
                        for (int i = 0; i < questionVo.getAnswer().length; i++) {
                            //用户答案index即该用户的选择，放入stringbuffer中比对答案表中的trueoption错误归入错题集字段errorquestion
                            if (questionVo.getAnswer()[i].getIstrue().equals("True")){
                                stringBuffer.append(i);
                                //存储内容格式如：1、计算机网络;
                                useranswer.append(questionVo.getQuestionid()).append("、").append(i).append(";");
                            }
                        }
                        if (stringBuffer.toString().equals(answers.get(k).getTrueoption())){
                            totalscore += questionVo.getScore();
                            scores.append(questionVo.getScore()).append(",");
                        }else {
                            errquestionids.append(questionVo.getQuestionid()).append(",");
                            scores.append(0).append(",");
                        }
                    }else if (questionVo.getQuestiontype() == 2){
                        for (int i = 0; i < questionVo.getAnswer().length; i++) {
                            if (i == 0){
                                useranswer.append(questionVo.getQuestionid()).append("、");
                                //这里获取用户的选择和单选异曲同工，不做过多解释
                                if (questionVo.getAnswer()[i].getIstrue().equals("True")){
                                    stringBuffer.append(i).append(",");
                                    useranswer.append(i).append(",");
                                }
                            }else {
                                if (questionVo.getAnswer()[i].getIstrue().equals("True")){
                                    stringBuffer.append(i).append(",");
                                    if (i == questionVo.getAnswer().length - 1){
                                        useranswer.append(i);
                                    }else {
                                        useranswer.append(i).append(",");
                                    }
                                }
                            }
                            if (i == questionVo.getAnswer().length - 1){
                                useranswer.append(";");
                            }
                        }
                        if (stringBuffer.toString().substring(0,stringBuffer.toString().length() - 1).equals(answers.get(k).getTrueoption())){
                            totalscore += questionVo.getScore();
                            scores.append(questionVo.getScore()).append(",");
                        }else {
                            errquestionids.append(questionVo.getQuestionid()).append(",");
                            scores.append(0).append(",");
                        }
                    }else if (questionVo.getQuestiontype() == 3){
                        //因为当初设计的问题，判断题存的是两个结果，即对应选择的true，false，故根据用户选择取到响应的string和该judge字段的答案比对
                        for (int i = 0; i < questionVo.getAnswer().length; i++) {
                            if (questionVo.getAnswer()[i].getIstrue().equals("True"))
                                if (i == questionVo.getAnswer().length - 1){
                                    stringBuffer.append("True").append(",");
                                    useranswer.append(questionVo.getAnswer()[i].getIstrue()).append(";");
                                } else{
                                    stringBuffer.append("True").append(",");
                                    useranswer.append(questionVo.getQuestionid()).append("、").append(questionVo.getAnswer()[i].getIstrue()).append(",");
                                }
                            else
                                if (i == questionVo.getAnswer().length - 1){
                                    stringBuffer.append("false").append(",");
                                    useranswer.append(questionVo.getAnswer()[i].getIstrue()).append(";");
                                } else{
                                    stringBuffer.append("false").append(",");
                                    useranswer.append(questionVo.getQuestionid()).append("、").append(questionVo.getAnswer()[i].getIstrue()).append(",");
                                }
                        }
                        if (stringBuffer.substring(0,stringBuffer.length() - 1).equals(answers.get(k).getJudge())){
                            totalscore += questionVo.getScore();
                            scores.append(questionVo.getScore()).append(",");
                        }else {
                            errquestionids.append(questionVo.getQuestionid()).append(",");
                            scores.append(0).append(",");
                        }
                    }else if (questionVo.getQuestiontype() == 4){
                        useranswer.append(questionVo.getQuestionid()).append("、").append(questionVo.getAnswer()[0].getAnswer()).append(";");
                        if (questionVo.getAnswer()[0].getAnswer().equals(answers.get(k).getText())){
                            totalscore += questionVo.getScore();
                            scores.append(questionVo.getScore()).append(",");
                        }else {
                            errquestionids.append(questionVo.getQuestionid()).append(",");
                            scores.append(0).append(",");
                        }
                    }else if (questionVo.getQuestiontype() == 6){
                        //问答题需要自主判分，故没有标准答案;答案表内也无数据可比对给分
                        useranswer.append(questionVo.getQuestionid()).append("、").append(questionVo.getAnswer()[0].getAnswer()).append(";");
//                        if (questionVo.getAnswer()[0].getText().equals(answers.get(k).getText())){
//                            totalscore += questionVo.getScore();
//                        }else {
//                            errquestionids.append(questionVo.getQuestionid()).append(",");
//                        }
                        scores.append(0).append(",");
                    }
                }
                k++;
            }
            examRecord.setTotalscore(totalscore);
            examRecord.setQuestionids(questionids.toString());
            examRecord.setErrorquestionids(errquestionids.toString());
            examRecord.setUseranswer(useranswer.toString());
            examRecord.setAnswername(answername);
            examRecord.setStarttime(starttime);
            examRecord.setEndtime(endtime);
            examRecord.setScore(scores.toString());
            examRecordMapper.insert(examRecord);
            result.setCode(200);
            result.setDetail(examRecord);
            result.setMsg("添加考试记录成功");
        }catch (Exception e){
            result.setMsg("添加考试记录失败");
            e.printStackTrace();
        }
        return result;
    }

    public int getExamRecordTotal(Integer examid){
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("examid",examid);
        List<ExamRecord> examRecordList = examRecordMapper.selectList(queryWrapper);
        return examRecordList.size();
    }

    public List scoreDistribution(Integer examid){
        int a = 0,b = 0,c = 0,d = 0,e = 0;
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("examid",examid);
        List<ExamRecord> examRecordList = examRecordMapper.selectList(queryWrapper);
        //遍历examrecord列表把取到的分数赋给该范围内的计数器，这里用到的计数器有点蠢，直接创建一个数组就可以有点画蛇添足了，主要对数组的应用不灵活吧
        for (ExamRecord examRecord : examRecordList) {
            if (examRecord.getTotalscore() >= 0 & examRecord.getTotalscore() < 20){
                a += 1;
            }else if (examRecord.getTotalscore() >= 20 & examRecord.getTotalscore() < 40){
                b += 1;
            }else if (examRecord.getTotalscore() >= 40 & examRecord.getTotalscore() < 60){
                c += 1;
            }else if (examRecord.getTotalscore() >= 60 & examRecord.getTotalscore() < 80){
                d += 1;
            }else if (examRecord.getTotalscore() >= 80 & examRecord.getTotalscore() < 100){
                e += 1;
            }
        }
        String[] str = new String[] {"product",FIRST_SCOPE,SECOND_SCOPE,THIRD_SCOPE,FORTH_SCOPE,FIFTH_SCOPE};
        int[] nums = new int[] {-1,a,b,c,d,e};
        List list = new ArrayList();
        //根据循环把结果放到list中
        for (int i = 0; i < str.length; i++) {
            List temp = new ArrayList();
            temp.add(str[i]);
            if (nums[i] == -1) {
                temp.add("人数");
            } else {
                temp.add(nums[i]);
            }
            list.add(temp);
        }
        return list;
    }

    @Override
    public List scoreData(Integer examid) {
        List<List> scoreDistribution = scoreDistribution(examid);
        int i = 0;
        List<Map> mapList = new ArrayList<>();
        int totalpeoples = 0;
        for (int j = 1; j <= scoreDistribution.size() - 1; j++) {
            String temp = scoreDistribution.get(j).get(1).toString();
            int perpeople = Integer.parseInt(temp);
            totalpeoples += perpeople;
        }
        //遍历scoreDistribution列表将需要的数据取出存到有序map中
        for (List o : scoreDistribution) {
            Map map = new LinkedHashMap();
            if (i == 0){
                i++;
                continue;
            }else {
                String temp = scoreDistribution.get(i).get(1).toString();
                int perpeople = Integer.parseInt(temp);
                //下面三行是一个取百分数的方法
                NumberFormat numberFormat = NumberFormat.getInstance();
                numberFormat.setMaximumFractionDigits(0);
                String result = numberFormat.format((float) perpeople / (float) totalpeoples * 100);
                map.put("num",i);
                map.put("score",o.get(0));
                map.put("people",o.get(1));
                map.put("bai",result+"%");
            }
            mapList.add(map);
            i++;
        }
        return mapList;
    }

    /**
     * 主要分为两步
     * 1、第一个for循环取errorquestion并判断每个用户每题的错误拿到响应题目计数器
     * 2、第二个for循环根据题数循环赋值、转化前端需要的数据格式
     * @param examid
     * @return list
     */
    @Override
    public List tableData(Integer examid) {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("examid",examid);
        List<Question> questions = questionMapper.selectList(queryWrapper);
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("examid",examid);
        List<ExamRecord> examRecords = examRecordMapper.selectList(wrapper);
        int[] no = new int[questions.size()];
        for (int i = 0; i < examRecords.size(); i++) {
            String strerrquids = examRecords.get(i).getErrorquestionids();
            String[] errquids = strerrquids.split(",");
            if (strerrquids.equals("")){
                for (int j = 0; j < questions.size(); j++) {
                    no[j] += 1;
                }
            }else {
                int[] errquidss =  Arrays.stream(errquids).mapToInt(Integer::parseInt).toArray();
                for (int j = 0; j < questions.size(); j++) {
                    for (int k = 0; k < errquidss.length; k++) {
                        if (errquidss[k] == questions.get(j).getId()){
                            no[j] += 1;
                            break;
                        }
                    }
                }
            }
        }
        List<Map> list = new ArrayList<>();
        for (int i = 1; i <= questions.size(); i++) {
            NumberFormat numberFormat = NumberFormat.getInstance();
            numberFormat.setMaximumFractionDigits(0);
            String result = numberFormat.format((float) no[i-1] / (float) examRecords.size() * 100);
            int num = Integer.parseInt(result);
            int x = 100 - num;
            String y = Integer.toString(x);
            Map map = new LinkedHashMap();
            if (questions.get(i-1).getQutype() == 5){
                continue;
            }
            map.put("num",i);
            map.put("questionTitle",questions.get(i-1).getQucontent());
            map.put("correct",y+"%");
            list.add(map);
        }
        return list;
    }

    /**
     * 计算排名的这个比较简单
     * 主要就是遍历examrecord表按总成绩高到低排序
     * 返回list，然后处理成前端需要的数据格式即可
     * @param examid
     * @return list
     */
    @Override
    public List rankData(Integer examid) {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.orderByDesc("totalscore");
        queryWrapper.eq("examid",examid);
        List<ExamRecord> examRecords = examRecordMapper.selectList(queryWrapper);
        List list = new ArrayList();
        int i = 1;
        for (ExamRecord examRecord : examRecords) {
            Map map = new LinkedHashMap();
            map.put("num",i);
            i++;
            map.put("score",examRecord.getTotalscore());
            map.put("longtime",examRecord.getExamtime());
            list.add(map);
        }
        return list;
    }

    /**
     * 这个方法的逻辑有点复杂，处理起来比较棘手
     * 该方法计算每题每个选项的答题人数
     * 当初在循环嵌套的地方遇到了坑，一下子脑袋短路
     * 外层循环次数为该试卷的题目数
     * 每次循环根据题目类型的不同定义统计选项的数组
     * 用了一个for循环取用户答案，这里就不赘述了
     * 统计的话主要就是拿到每张答卷的数据根据题目类型一一比对答案
     * 增加对应计数器的值，最后再用一个for循环赋值给前端需要的数据格式
     * @param examid
     * @param questionVoList
     * @return
     */
    @Override
    public List resData(Integer examid, List<QuestionVo> questionVoList) {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("examid",examid);
        List<ExamRecord> examRecords = examRecordMapper.selectList(queryWrapper);
        List<Map> maps = new ArrayList<>();
        int k = 0;
        for (QuestionVo questionVo : questionVoList) {
            Map resmap = new LinkedHashMap();
            //根据不同题目类型的不同创建计数的数组大小也不同
            int[] nums = new int[questionVo.getAnswer().length];
            for (int i = 0; i < examRecords.size(); i++) {
                //将useranswer里的答案按";"分开生成一个string数组
                String[] str = examRecords.get(i).getUseranswer().split(";");
                //该数组用来存储剔除了题号的答案
                String[] str1 = new String[str.length];
                for (int i1 = 0; i1 < str.length; i1++) {
                    String[] str2 = str[i1].split("、");
                    for (int j = 0; j < str2.length; j++) {
                        if (j == 0) {
                            continue;
                        }
                        str1[i1] = str2[j];
                    }
                }
                if (questionVo.getQuestiontype() == 1){
                    for (int j = 0; j < questionVo.getAnswer().length; j++) {
                        int x = Integer.parseInt(str1[k]);
                        if (x == j){
                            nums[j] += 1;
                        }
                    }
                }else if (questionVo.getQuestiontype() == 2){
                    String[] multistr = str1[k].split(",");
                    for (int j = 0; j < questionVo.getAnswer().length; j++) {
                        for (int l = 0; l < multistr.length; l++) {
                            int y = Integer.parseInt(multistr[l]);
                            if (y == j){
                                nums[j] += 1;
                                break;
                            }
                        }
                    }
                }else if (questionVo.getQuestiontype() == 3){
                    QueryWrapper<Answer> wrapper = new QueryWrapper<>();
                    wrapper.eq("questionid",questionVo.getQuestionid());
                    Answer answer = answerMapper.selectOne(wrapper);
                    if (str1[k].equals(answer.getJudge())){
                        nums[0]++;
                    }else {
                        nums[1]++;
                    }
                }
            }
            List<Map> mapList = new ArrayList<>();
            for (int j = 0; j < questionVo.getAnswer().length; j++) {
                if (questionVo.getQuestiontype() == 5){
                    continue;
                }else {
                    Map map = new LinkedHashMap();
                    for (int l = 0; l < 2; l++) {
                        if (l == 0){
                            map.put("name",questionVo.getAnswer()[j].getAnswer());
                        }else {
                            NumberFormat numberFormat = NumberFormat.getInstance();
                            numberFormat.setMaximumFractionDigits(0);
                            String result = numberFormat.format((float) nums[j] / (float) examRecords.size() * 100);
                            int change = Integer.parseInt(result);
                            map.put("value",change);
                        }
                    }
                    mapList.add(map);
                }
            }
            if (questionVo.getQuestiontype() == 5){
                k++;
                continue;
            }else {
                resmap.put("resData",mapList);
                maps.add(resmap);
            }
            k++;
        }

        return maps;
    }

    /**
     * 这个方法主要就是遍历列表里的每个数据
     * 将需要的东西拿出来返回前端就是了
     * @param examid
     * @return
     */
    @Override
    public List dataDetail(Integer examid) {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("examid",examid);
        List<ExamRecord> examRecords = examRecordMapper.selectList(queryWrapper);
        int i = 1;
        List<Map> mapList = new ArrayList<>();
        for (ExamRecord examRecord : examRecords) {
            Map map = new LinkedHashMap();
            map.put("num",examRecord.getRecordid());
            map.put("name",examRecord.getAnswername());
            map.put("score",examRecord.getTotalscore());
            map.put("starttime",examRecord.getStarttime());
            map.put("endtime",examRecord.getEndtime());
            map.put("longtime",examRecord.getExamtime());
            mapList.add(map);
            i++;
        }
        return mapList;
    }

    /**
     * 这是一个展示所有统计结果的方法
     * 因为比较简单就不过多讲解思路了
     * 将以上所有统计的方法全部放入一个map里即可
     * @param examid
     * @return
     */
    @Override
    public Map showInfo(Integer examid, List<QuestionVo> questionVoList) {
        Map map = new LinkedHashMap();
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("examid",examid);
        List<ExamRecord> examRecord = examRecordMapper.selectList(queryWrapper);
        if (examRecord == null){
            return null;
        }else {
            map.put("source",scoreDistribution(examid));
            map.put("scoreData",scoreData(examid));
            map.put("tableData",tableData(examid));
            map.put("rankData",rankData(examid));
            map.put("resData",resData(examid,questionVoList));
            map.put("dataDetail",dataDetail(examid));
        }
        return map;
    }

    /**
     * 将用户的答案处理成 ”0；1，2；这是填空题；“
     * 这样的格式前端渲染拿到数据简单处理后
     * 渲染出用户的答卷，“；”隔开每个题目
     * @param recordid
     * @return
     */
    public Map userAnswer(Integer recordid){
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("recordid",recordid);
        ExamRecord examRecord = examRecordMapper.selectOne(queryWrapper);
        if (examRecord == null){
            return null;
        }
        String useranswer = examRecord.getUseranswer();
        String[] struseranswer = useranswer.split(";");
        StringBuffer stringBuffer = new StringBuffer();
        String[] str = new String[struseranswer.length];
        for (int i = 0; i < struseranswer.length; i++) {
            String[] str1 = struseranswer[i].split("、");
            for (int j = 0; j < str1.length; j++) {
                if (j == 0) {
                    continue;
                }
                str[i] = str1[j];
            }
            stringBuffer.append(str[i]).append(";");
        }
        Map map = new LinkedHashMap();
        map.put("errorquestions",examRecord.getErrorquestionids());
        map.put("useranswer",stringBuffer.toString());
        map.put("score",examRecord.getScore());
        return map;
    }


    /**
     * 前端自主判分后拿到
     * 后端修改相关总分即可
     * @param examRecord
     * @return
     */
    public Result updateScore(ExamRecord examRecord){
        Result result = new Result();
        result.setCode(-1);
        result.setDetail(null);
        try {
            examRecordMapper.updateScore(examRecord);
            result.setCode(200);
            result.setMsg("更新批改后的成绩成功");
        }catch (Exception e){
            e.printStackTrace();
        }
        return result;
    }

}
